<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <title>商品管理系统</title>
    <script src="js/vue.js"></script>
    <script src="js/element-ui/lib/index.js"></script>
    <link rel="stylesheet" href="js/element-ui/lib/theme-chalk/index.css">
    <script src="js/axios-0.18.0.js"></script>
    <!-- Element UI 样式 -->
<!--    <link rel="stylesheet" href="https://unpkg.com/element-ui/lib/theme-chalk/index.css">-->
    <!-- Vue.js -->
<!--    <script src="https://unpkg.com/vue@2.6.14/dist/vue.js"></script>-->
    <!-- Element UI 组件库 -->
<!--    <script src="https://unpkg.com/element-ui/lib/index.js"></script>-->
    <!-- Axios 网络请求 -->
<!--    <script src="https://unpkg.com/axios/dist/axios.min.js"></script>-->
    <!-- 图标库 -->
    <link rel="stylesheet" href="https://unpkg.com/font-awesome@4.7.0/css/font-awesome.min.css">
    <style>
        .container { padding: 20px; }
        .el-table { margin-top: 20px; }
        .image-item { display: inline-block; margin: 5px; position: relative; }
        .image-item img { width: 100px; height: 100px; object-fit: cover; }
        .text-danger { color: #F56C6C; }
        .upload-dragger { border: 2px dashed #e6e6e6; border-radius: 6px; text-align: center; padding: 30px 0; }
        .specifications-editor {
            display: flex;
            flex-wrap: wrap;
            gap: 10px;
            margin-top: 10px;
        }
        .key-value-item {
            display: flex;
            gap: 10px;
            margin-bottom: 5px;
            width: 100%;
        }
        .key-input {
            flex: 1;
            min-width: 150px;
        }
        .value-input {
            flex: 2;
            min-width: 300px;
        }
        .add-button {
            margin-top: 10px;
            width: 100%;
        }
        .image-item {
            position: relative;
            display: inline-flex; /* 改为弹性布局 */
            flex-direction: column; /* 垂直排列图片和排序框 */
            align-items: center; /* 内容居中 */
            margin: 10px; /* 增加间距 */
            padding: 5px; /* 增加内边距 */
            border: 1px solid #e4e7ed; /* 添加边框 */
            border-radius: 4px; /* 圆角 */
            box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05); /* 阴影效果 */
        }

        .image-item img {
            width: 120px; /* 增大图片尺寸 */
            height: 120px; /* 增大图片尺寸 */
            object-fit: cover; /* 保持图片比例 */
            margin-bottom: 8px; /* 图片与排序框间距 */
        }

        /* 排序框样式优化 */
        .el-input-number {
            position: static !important; /* 取消绝对定位 */
            margin-top: 4px; /* 排序框与图片间距 */
            width: 100%; /* 撑满容器宽度 */
            max-width: 80px; /* 限制最大宽度 */
        }

        /* 删除按钮样式优化 */
        .image-item .el-icon-close {
            position: absolute;
            top: 5px;
            right: 5px;
            font-size: 14px;
            color: #ff4949;
            background: #ffffff;
            border-radius: 50%;
            padding: 2px;
            box-shadow: 0 0 4px rgba(0, 0, 0, 0.1);
        }

        /* 上传进度样式 */
        .uploading-mask {
            position: absolute;
            top: 0;
            left: 0;
            width: 100%;
            height: 100%;
            background: rgba(255, 255, 255, 0.8);
            display: flex;
            align-items: center;
            justify-content: center;
        }
        @media (max-width: 768px) {
            .image-item {
                margin: 8px;
                width: calc(50% - 16px); /* 小屏显示2列 */
            }

            .image-item img {
                width: 100%;
                height: 80px;
            }
        }

        @media (min-width: 769px) and (max-width: 1024px) {
            .image-item {
                margin: 10px;
                width: calc(33.33% - 20px); /* 中等屏幕显示3列 */
            }
        }

        @media (min-width: 1025px) {
            .image-item {
                width: calc(20% - 20px); /* 大屏显示5列 */
            }
        }
        .image-item .el-icon-delete {
            position: absolute;
            top: -8px;
            right: -8px;
            font-size: 16px;
            color: #ff4949;
            background: #fff;
            border-radius: 50%;
            padding: 3px;
            box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
            z-index: 10; // 确保层级高于图片
        }
    </style>
</head>
<body>
<div id="app" class="container">
    <!-- 顶部操作栏 -->
    <el-row :gutter="20">
        <el-col :span="18">
            <el-input
                    v-model="search.keyword"
                    placeholder="搜索商品编号/名称"
                    prefix-icon="el-icon-search"
                    @keyup.enter.native="searchProducts"

            ></el-input>
        </el-col>
        <el-col :span="6">
            <el-button
                    type="primary"
                    @click="openAddDialog"
                    icon="el-icon-plus"
            >新增商品</el-button>
        </el-col>
    </el-row>

    <!-- 商品列表 -->
    <el-table
            :data="products"
            stripe
            border
            v-loading="loading"
            style="width: 100%; margin-top: 20px"
    >
        <el-table-column prop="productId" label="商品ID" width="80"></el-table-column>
        <el-table-column prop="productNumber" label="商品编号" width="120"></el-table-column>
        <el-table-column prop="productName" label="商品名称"></el-table-column>
        <el-table-column label="价格" width="100">
            <template slot-scope="scope">￥{{ scope.row.price }}</template>
        </el-table-column>
        <el-table-column label="库存">
            <template slot-scope="scope">
                <span :class="scope.row.stock < scope.row.stockAlertThreshold? 'text-danger' : ''">
                    {{ scope.row.stock }}
                    <el-tooltip content="库存不足" effect="light" v-if="scope.row.stock < scope.row.stockAlertThreshold">
                        <i class="el-icon-warning" style="margin-left: 5px; color: #F56C6C"></i>
                    </el-tooltip>
                </span>
            </template>
        </el-table-column>
        <el-table-column label="上架状态" width="100">
            <template slot-scope="scope">
                <el-switch
                        v-model="scope.row.isPublished"
                        :active-value="1"
                        :inactive-value="0"
                        @change="togglePublish(scope.row.productId, $event)"
                        active-color="#409EFF"
                        inactive-color="#F56C6C"
                ></el-switch>
            </template>
        </el-table-column>
        <el-table-column label="操作" width="200">
            <template slot-scope="scope">
                <el-button
                        size="mini"
                        type="primary"
                        @click="openEditDialog(scope.row)"
                        icon="el-icon-edit"
                        class="mr-5"
                >编辑</el-button>
                <el-button
                        size="mini"
                        type="danger"
                        @click="deleteProduct(scope.row.productId)"
                        icon="el-icon-delete"
                >删除</el-button>
            </template>
        </el-table-column>
    </el-table>

    <el-pagination
            :current-page="currentPage"
            :page-sizes="[5, 10, 20]"
            :page-size="pageSize"
            :total="total"
            style="text-align: center; margin-top: 20px"
            layout="total, sizes, prev, pager, next, jumper"
            @size-change="handleSizeChange"
            @current-change="handleCurrentChange"
    ></el-pagination>
    <!-- 新增/编辑对话框 -->
    <el-dialog
            title="商品管理"
            :visible.sync="dialogVisible"
            width="80%"
            :before-close="beforeClose"
    >
        <!-- 将整个表单移到标签页外部 -->
        <el-form
                :model="form"
                :rules="rules"
                ref="formRef"
                label-width="100px"
        >
            <el-tabs v-model="activeTab" type="card">
                <el-tab-pane label="基础信息">
                    <el-form-item label="商品编号" prop="productNumber">
                        <el-input
                                v-model="form.productNumber"
                                :disabled="dialogType!== 'add'"
                                placeholder="请输入唯一编号"
                        ></el-input>
                    </el-form-item>
                    <el-form-item label="商品名称" prop="productName">
                        <el-input
                                v-model="form.productName"
                                required
                                placeholder="请输入商品名称"
                        ></el-input>
                    </el-form-item>

                    <!-- 新增：商品目录级联选择器 -->
                    <el-form-item label="商品目录" prop="category">
                        <el-cascader
                                v-model="form.categoryPath"
                                :options="categoryTree"
                                :props="cascaderProps"
                                placeholder="请选择商品目录"
                                clearable
                                :show-all-levels="false"
                                required
                        >
                            <!-- 自定义触发输入框（解决样式问题） -->
                            <template #trigger="trigger">
                                <el-input
                                        v-model="trigger.inputValue"
                                        :placeholder="trigger.placeholder"
                                        @focus="trigger.onFocus"
                                        @blur="trigger.onBlur"
                                        @click="trigger.onFocus"
                                        style="width: 100%"
                                ></el-input>
                            </template>
                        </el-cascader>
                    </el-form-item>
                    <!-- 价格、库存等字段 -->
                    <el-form-item label="价格" prop="price">
                        <el-input
                                v-model="form.price"
                                required
                                placeholder="请输入价格"
                        ></el-input>
                    </el-form-item>
                    <el-form-item label="库存" prop="stock">
                        <el-input
                                v-model="form.stock"
                                required
                                placeholder="请输入库存"
                        ></el-input>
                    </el-form-item>
                    <el-form-item label="库存预警阈值" prop="stockAlertThreshold">
                        <el-input
                                v-model="form.stockAlertThreshold"
                                required
                                placeholder="请输入库存预警阈值"
                        ></el-input>
                    </el-form-item>
                </el-tab-pane>

                <el-tab-pane label="详细信息">
                    <!-- 将这些表单元素也放在表单内 -->
                    <el-form-item label="图文描述">
                        <el-input
                                type="textarea"
                                v-model="form.description"
                                rows="5"
                                placeholder="请输入商品描述"
                        ></el-input>
                    </el-form-item>
                    <!-- 新增：动态键值对编辑器 -->
                    <el-form-item label="规格参数">
                        <div class="specifications-editor">
                            <div v-for="(item, index) in specItems" :key="index" class="key-value-item">
                                <el-input
                                        v-model="item.key"
                                        placeholder="请输入参数名称（如屏幕尺寸）"
                                        class="key-input"
                                        @blur="handleKeyBlur(index)"
                                        :rules="{ required: true, message: '参数名称不能为空', trigger: 'blur' }"
                                ></el-input>
                                <el-input
                                        v-model="item.value"
                                        placeholder="请输入参数值（如6.5英寸）"
                                        class="value-input"
                                ></el-input>
                                <el-button
                                        type="danger"
                                        size="mini"
                                        @click="removeItem(index)"
                                        v-if="specItems.length > 1"
                                >删除</el-button>
                            </div>
                            <el-button
                                    type="primary"
                                    size="small"
                                    @click="addItem"
                                    class="add-button"
                            >添加参数</el-button>
                        </div>
                    </el-form-item>
                </el-tab-pane>

                <el-tab-pane label="商品图片">
                    <!-- 同样，将上传组件放在表单内 -->
                    <el-form-item label="商品图片">
                        <el-upload
                                class="upload-dragger"
                                :file-list="uploadFiles"
                                :action="ossUploadUrl"
                                :on-preview="handlePreview"
                                :on-remove="handleRemove"
                                :on-success="handleUploadSuccess"
                                :on-error="handleUploadError"
                                :on-progress="handleProgress"
                                multiple
                                drag
                                :auto-upload="true"
                                :before-upload="beforeUpload"
                        >
                            <i class="el-icon-upload"></i>
                            <div class="el-upload__text">将文件拖到此处，或点击上传</div>
                            <div class="el-upload__hint">仅支持JPG/PNG文件，最大5MB</div>
                        </el-upload>

                        <div class="image-container" v-if="uploadFiles.length > 0">
                            <div v-for="(image, index) in uploadFiles" :key="image.uid" class="image-item">
                                <!-- 图片预览 -->
                                <img :src="image.url || image.response?.data?.url" alt="" class="preview-image">

                                <!-- 排序框（移除绝对定位，改为弹性布局内的块元素） -->
                                <el-input-number
                                        v-model="image.sortOrder"
                                        :min="1"
                                        size="mini"
                                        class="sort-order"
                                        placeholder="排序号"
                                ></el-input-number>

                                <!-- 删除按钮 -->
                                <i class="el-icon-close" @click="handleRemove(image, uploadFiles)"></i>

                                <!-- 上传进度 -->
                                <div v-if="image.status === 'uploading'" class="uploading-mask">
                                    <el-progress :percentage="image.percentage || 0" type="circle" :width="60"></el-progress>
                                </div>
                            </div>
                        </div>
                    </el-form-item>
                </el-tab-pane>
            </el-tabs>
        </el-form>

        <div slot="footer" class="dialog-footer">
            <el-button @click="dialogVisible = false">取消</el-button>
            <el-button
                    type="primary"
                    @click="submitForm"
            >
                {{ dialogType === 'add'? '新增商品' : '保存修改' }}
            </el-button>
        </div>
    </el-dialog>

</div>

<script>
    // 配置Axios基础URL（需替换为实际后端地址）
    axios.defaults.baseURL = 'http://localhost:8001';

    new Vue({
        el: '#app',
        data() {
            return {
                search: { keyword: '' },
                products: [],
                loading: false,
                dialogVisible: false,
                dialogType: 'add',
                activeTab: 'base',
                uploadFiles: [],  // 存储上传中的文件
                // 新增：规格参数键值对数组
                specItems: [],
                tempSpecs: {},
                form: {
                    productId: null,
                    productNumber: '',
                    productName: '',
                    price: '', // 字符串类型，适应表单输入
                    categoryPath: [],
                    categoryId: '',
                    stock: '',
                    stockAlertThreshold: '',
                    isPublished: 1, // 保持 1/0（与数据库一致）
                    description: '',
                    specifications: '',
                },
                categoryTree: [], // 分类树数据
                cascaderProps: {
                    label: 'categoryName',
                    value: 'categoryId',
                    children: 'children',
                    expandTrigger: 'click', // 点击展开更稳定
                    checkStrictly: true // 取消父子级联动（可选）
                },
                rules: {
                    productNumber: [{ required: true, message: '请输入商品编号', trigger: 'blur' }],
                    productName: [{ required: true, message: '请输入商品名称', trigger: 'blur' }],
                    price: [
                        { required: true, message: '请输入价格', trigger: 'blur' },
                        { type: 'number', message: '请输入有效数字', trigger: 'blur',  transform: value => Number(value)}
                    ],
                    stock: [
                        { required: true, message: '请输入库存', trigger: 'blur' },
                        { type: 'number', message: '请输入有效数字', trigger: 'blur',  transform: value => Number(value) }
                    ],
                    stockAlertThreshold: [
                        { required: true, message: '请输入库存预警阈值', trigger: 'blur' },
                        { type: 'number', message: '请输入有效数字', trigger: 'blur',transform: value => Number(value) }
                    ]
                },
                ossUploadUrl: 'http://localhost:8001/oss/upload', // OSS上传接口
                currentPage: 1,
                pageSize: 5,
                total: 0
            };
        },
        methods: {
            loadCategoryTree() {
                axios.get('/category')
                    .then(res => {
                        if (res.data.code === 20041) {
                            // 处理数据：去除 Vue 观测器，确保字段正确
                            const cleanData = res.data.data.map(node => {
                                const { __ob__, ...cleanNode } = node; // 移除 __ob__
                                return cleanNode;
                            });
                            this.categoryTree = this.buildTree(cleanData);
                        }
                    })
                    .catch(err => {
                        console.error('分类树加载失败:', err);
                        this.$message.error('分类树加载失败，请重试');
                    });
            },
            buildTree(list) {
                const nodeMap = new Map();
                const tree = [];
                list.forEach(node => {
                    nodeMap.set(node.categoryId, { ...node, children: [] });
                });
                list.forEach(node => {
                    const parentId = node.parentId || 0; // 处理 parentId 为 null 的情况
                    if (parentId === 0) {
                        tree.push(nodeMap.get(node.categoryId));
                    } else {
                        const parentNode = nodeMap.get(parentId);
                        if (parentNode) {
                            parentNode.children.push(nodeMap.get(node.categoryId));
                        }
                    }
                });
                return tree;
            },
            handleUploadSuccess(response, file, fileList) {
                if (!response || response.code !== 20011) {
                    this.$message.error('图片上传失败');
                    this.handleRemove(file, fileList);
                    return;
                }

                const imageUrl = response.data; // 假设 response.data 是图片URL
                const index = this.uploadFiles.findIndex(f => f.uid === file.uid);

                if (index !== -1) {
                    // 新增图片：id 设为 null（后端新增时自动生成）
                    // 编辑图片：id 来自原有数据（通过 openEditDialog 初始化）
                    this.$set(this.uploadFiles[index], {
                        ...this.uploadFiles[index],
                        url: imageUrl,
                        status: 'success',
                        percentage: 100,
                        id: null, // 新增图片无ID，编辑时保留原有ID
                        response: { data: imageUrl } // 可选：保留原始响应数据
                    });
                } else {
                    // 处理异常情况（如 uid 丢失，手动添加新文件）
                    this.uploadFiles.push({
                        uid: file.uid,
                        name: file.name,
                        url: imageUrl,
                        status: 'success',
                        sortOrder: 1,
                        id: null
                    });
                }

                this.$message.success('图片上传成功');
            },
            handleUploadError(error, file, fileList) {
                this.$message.error('图片上传失败');

                // 更新文件状态
                const index = this.uploadFiles.findIndex(f => f.uid === file.uid);
                if (index !== -1) {
                    this.$set(this.uploadFiles[index], 'status', 'fail');
                    this.$set(this.uploadFiles[index], 'percentage', 0);
                }
            },
            init(){
                axios({
                    method: "post",
                    url:`/products`,
                    data:{
                        currentPage: this.currentPage,
                        pageSize: this.pageSize,
                        keyword: this.search.keyword
                    }
                }).then((resp)=>{
                    console.log(resp)
                    var page=resp.data.data
                    this.products=page.list
                    this.total=page.totals
                })
            },
            searchProducts() {
                this.currentPage = 1; // 重置到第一页
                this.init(); // 执行搜索逻辑
            },

            handleCurrentChange(page) {
                this.currentPage = page;
                this.init();
            },
            handleSizeChange(size) {
                this.pageSize = size;
                this.init();
            },


            // 上架/下架切换
            async togglePublish(productId, isPublished) {
                try {
                    // 发送整数类型到后端
                    await axios.put(`/products/${productId}/publish`,null,{
                        params: {
                            isPublished
                        }
                    });

                    this.$message.success('状态更新成功');
                    const target = this.products.find(p => p.productId === productId);
                    target.isPublished = isPublished;  // 更新本地数据
                } catch (error) {
                    console.error('状态更新失败:', error.response?.data);
                    this.$message.error('状态更新失败，请重试');

                    // 回滚本地状态
                    const target = this.products.find(p => p.productId === productId);
                    target.isPublished = isPublished ? 0 : 1;
                }
            },

            // 打开对话框
            openAddDialog() {
                this.dialogType = 'add';
                this.resetForm();
                this.dialogVisible = true;
            },

            openEditDialog(row) {
                this.dialogType = 'edit';

                this.form.description = row.productDetails?.description || '';
                // 安全获取规格参数（使用 productDetails 和可选链）
                this.form.specifications = row.productDetails?.specifications || '{}';
                this.initSpecifications(); // 解析现有规格参数
                // 处理图片数据，确保包含 Element UI 所需字段（如 name、url）
                const images = (row.productImages || []).map(img => ({
                    id: img.imageId,
                    url: img.imageUrl,
                    sortOrder: img.sortOrder,
                    // 为了兼容 el-upload 的显示，添加 name 和 status
                    name: img.imageUrl.split('/').pop(),
                    status: 'success',
                    uid: img.imageId || Date.now()
                }));
                this.form = {
                    ...row,
                    images: images, // 转换后的图片列表
                    price: row.price.toString(), // 价格转为字符串，适应表单输入
                    stock: row.stock.toString(),
                    stockAlertThreshold: row.stockAlertThreshold.toString(),
                    description: row.productDetails?.description || '' // 确保 description 赋值
                };
                // 处理商品目录回显
                const categoryId = row.categoryId;
                if (categoryId) {
                    this.form.categoryPath = this.findCategoryPath(categoryId);
                }
                // 同步到 uploadFiles
                this.uploadFiles = [...images];
                this.dialogVisible = true;
            },
            // 添加辅助方法：查找分类路径
            findCategoryPath(categoryId) {
                // 递归查找分类路径
                const findPath = (node, targetId, path = []) => {
                    if (node.categoryId === targetId) {
                        return [...path, node.categoryId];
                    }

                    if (node.children && node.children.length > 0) {
                        for (const child of node.children) {
                            const result = findPath(child, targetId, [...path, node.categoryId]);
                            if (result) return result;
                        }
                    }

                    return null;
                };

                // 在分类树中查找路径
                for (const rootNode of this.categoryTree) {
                    const path = findPath(rootNode, categoryId);
                    if (path) return path;
                }

                return []; // 未找到路径
            },
            // 表单提交
            async submitForm() {
                try {
                    await this.$refs.formRef.validate();
                    this.form.categoryId = this.form.categoryPath.at(-1);
                    this.form.specifications = this.generateSpecificationsJson();
                    if (!this.form.specifications.trim()) {
                        this.form.specifications = '{}'; // 或 '[]'，根据业务需求
                    }
                    // 转换数值类型
                    this.form.price = Number(this.form.price);
                    this.form.stock = Number(this.form.stock);
                    this.form.stockAlertThreshold = Number(this.form.stockAlertThreshold);

                    const requestData = {
                        product: {
                            productNumber: this.form.productNumber,
                            productName: this.form.productName,
                            categoryId: this.form.categoryId,
                            price: this.form.price,
                            stock: this.form.stock,
                            stockAlertThreshold: this.form.stockAlertThreshold,
                            isPublished: this.form.isPublished // 上架状态
                        },
                        details: {

                            description: this.form.description,
                            specifications: this.form.specifications
                        },
                        images: this.uploadFiles
                            .filter(img => img.status === 'success'|| img.status === 'uploading') // 过滤出上传成功的图片
                            .map(img => ({
                                imageId: img.id || null, // 新增图片设为 null，避免传递 undefined
                                imageUrl: img.url, // 直接使用已存储的 url
                                sortOrder: img.sortOrder || 1 // 默认排序号为 1（如果未设置）
                            }))
                    };
                    // 继续提交逻辑
                    let res;
                    if (this.dialogType === 'add') {
                        res = await axios.post('/products/add', requestData);
                    } else {
                        res = await axios.put(`/products/${this.form.productId}`, requestData);
                    }
                    // 处理响应
                    if (res.data.code === 20031) { // 假设后端成功响应码为 200
                        this.$message.success(res.data.msg);
                        this.dialogVisible = false;
                        this.init();
                    } else  if (res.data.code === 20011){
                        this.$message.success(res.data.msg);
                        this.dialogVisible = false;
                        this.init();
                    }else{
                        this.$message.error(res.data.msg || '操作失败，请重试');
                    }


                } catch (error) {
                    console.error('提交失败:', {
                        message: error.message,  // 错误消息
                        response: error.response?.data,  // 响应数据
                        request: error.request,  // 请求对象
                        config: error.config,    // 请求配置
                    });

                    // 根据不同错误类型显示不同提示
                    if (error.response) {
                        // 服务器返回错误状态码（如 400、500）
                        const msg = error.response.data?.msg || `请求失败，状态码: ${error.response.status}`;
                        this.$message.error(msg);
                    } else if (error.request) {
                        // 请求已发送，但没有收到响应
                        this.$message.error('服务器无响应，请稍后重试');
                    } else {
                        // 设置请求时出错
                        this.$message.error('请求配置错误: ' + error.message);
                    }
                }
            },

            // 图片处理
            beforeUpload(file) {
                const isJPG = file.type.match(/image\/(jpeg|png)/);
                const isLt5M = file.size / 1024 / 1024 < 5;

                if (!isJPG) {
                    this.$message.error('仅支持 JPG/PNG 格式');
                    return false;
                }
                if (!isLt5M) {
                    this.$message.error('文件大小不超过 5MB');
                    return false;
                }

                // 添加到上传队列，初始化进度
                // this.uploadFiles.push({
                //     name: file.name,
                //     status: 'uploading',
                //     percentage: 0,
                //     sortOrder: this.uploadFiles.length + 1,
                //     uid: file.uid
                // });

                return true;
            },
            handleProgress(event, file, fileList) {
                const percentage = Math.floor((event.loaded / event.total) * 100);
                const index = this.uploadFiles.findIndex(f => f.uid === file.uid);
                if (index !== -1) {
                    this.$set(this.uploadFiles[index], {
                        percentage,
                        status: 'uploading',
                        // 新增透明度动画
                        opacity: percentage < 100 ? 0.5 : 1,
                    });
                }
            },
            async uploadToOss(file) {
                const formData = new FormData();
                formData.append('file', file);
                try {
                    const res = await axios.post(this.ossUploadUrl, formData, {
                        headers: { 'Content-Type': 'multipart/form-data' }
                    });
                    if (res.data.code === Code.SAVE_OK) {
                        const imageUrl = res.data.data.url; // 假设后端返回图片 URL
                        this.form.images.push({
                            url: imageUrl,
                            sortOrder: 0,
                            // 其他字段如 imageId（新增时可能不需要，编辑时需保留）
                        });
                        return false; // 阻止自动上传（若使用手动上传）
                    }
                } catch (error) {
                    this.$message.error('图片上传失败');
                    console.error('OSS 上传错误:', error);
                }
            },

            handlePreview(file) {
                this.$alert(`<img src="${file.url}" style="max-width: 400px">`, '图片预览', {
                    dangerouslyUseHTMLString: true
                });
            },

            removeImage(image) {
                this.form.images = this.form.images.filter(img => img.id!== image.id);
                // 调用后端删除接口（需补充）


            },

            // 重置表单
            resetForm() {
                this.form = {
                    productId: null,
                    productNumber: '',
                    productName: '',
                    price: 0,
                    stock: 0,
                    stockAlertThreshold: 0,
                    isPublished: 1,
                    description: '',
                    specifications: '',
                    images: []
                };
                this.specItems = []; // 清空规格参数
                this.uploadFiles = [];
            },

            // 搜索
            searchProducts() {
                this.init();
            },

            // 删除商品
            async deleteProduct(productId) {
                this.$confirm('确认删除该商品？删除后不可恢复', '提示', {
                    confirmButtonText: '确定',
                    cancelButtonText: '取消',
                    type: 'warning'
                }).then(async () => {
                    await axios.delete(`/products/${productId}`);
                    this.$message.success('删除成功');
                    this.init();
                });
            },

            beforeClose(done) {
                this.$refs.formRef.resetFields();
                this.resetForm(); // 调用重置方法
                done();
            },
            handleRemove(file, fileList) {
                // 1. 从前端列表移除图片
                this.uploadFiles = fileList;

                // 2. 判断是否为已上传的图片（有 url 且状态为 success）
                const isUploaded = file.status === 'success' && file.url;

                if (isUploaded) {
                    // 3. 从 URL 中提取文件名（假设 URL 格式为 /image/文件名.jpg）
                    const fileName = file.url.split('/').pop();

                    if (fileName) {
                        // 4. 确认删除
                        this.$confirm('是否删除服务器上的图片？', '提示', {
                            confirmButtonText: '确定',
                            cancelButtonText: '取消',
                            type: 'warning'
                        }).then(async () => {
                            try {
                                // 5. 调用后端删除接口
                                await axios.delete(`/oss/delete/${fileName}`);
                                this.$message.success('服务器图片已删除');
                            } catch (error) {
                                this.$message.error('服务器图片删除失败');
                                console.error('删除失败:', error);
                            }
                        });
                    }
                }
            },
            //规格参数
            initSpecifications() {
                // 新增商品时，默认空数组
                if (this.dialogType === 'add') {
                    this.specItems = [{ key: '', value: '' }];
                }
                // 编辑商品时，解析现有JSON
                if (this.dialogType === 'edit' && this.form.specifications) {
                    try {
                        this.tempSpecs = JSON.parse(this.form.specifications);
                        this.specItems = Object.entries(this.tempSpecs).map(([key, value]) => ({ key, value }));
                    } catch (error) {
                        this.$message.error('规格参数解析失败，已重置为默认');
                        this.specItems = [{ key: '', value: '' }];
                    }
                }
            },

            // 添加参数项
            addItem() {
                this.specItems.push({ key: '', value: '' });
            },

            // 删除参数项
            removeItem(index) {
                if (this.specItems.length === 1) return; // 至少保留一个输入框
                this.specItems.splice(index, 1);
            },

            // 校验参数名称唯一性
            handleKeyBlur(index) {
                const currentKey = this.specItems[index].key.trim();
                if (!currentKey) return; // 空值由表单校验处理

                // 检查重复键
                const hasDuplicate = this.specItems.some(
                    (item, i) => i !== index && item.key.trim() === currentKey
                );
                if (hasDuplicate) {
                    this.$message.error('参数名称不能重复');
                    this.specItems[index].key = ''; // 清空重复项
                }
            },

            // 生成最终JSON字符串
            generateSpecificationsJson() {
                return JSON.stringify(
                    this.specItems.reduce((acc, item) => {
                        const key = item.key.trim();
                        const value = item.value.trim();
                        if (key && value) acc[key] = value; // 过滤空键或空值
                        return acc;
                    }, {}) || {} // 确保返回非空JSON
                );
            }
        },
        mounted() {
            this.init();
            this.loadCategoryTree();
        }
    });
</script>
</body>
</html>